package metrics

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/go-redis/redis/v8"
)

// Metric 指标接口
type Metric interface {
	Name() string
	Update(value float64)
	Reset()
}

// Counter 计数器指标
type Counter struct {
	name  string
	value float64
	mu    sync.Mutex
}

// NewCounter 创建计数器
func NewCounter(name string) *Counter {
	return &Counter{
		name:  name,
		value: 0,
	}
}

// Name 获取指标名称
func (c *Counter) Name() string {
	return c.name
}

// Update 更新计数器值
func (c *Counter) Update(value float64) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.value += value
}

// Reset 重置计数器
func (c *Counter) Reset() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.value = 0
}

// Value 获取计数器值
func (c *Counter) Value() float64 {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.value
}

// Gauge 仪表盘指标
type Gauge struct {
	name  string
	value float64
	mu    sync.Mutex
}

// NewGauge 创建仪表盘
func NewGauge(name string) *Gauge {
	return &Gauge{
		name:  name,
		value: 0,
	}
}

// Name 获取指标名称
func (g *Gauge) Name() string {
	return g.name
}

// Update 更新仪表盘值
func (g *Gauge) Update(value float64) {
	g.mu.Lock()
	defer g.mu.Unlock()
	g.value = value
}

// Reset 重置仪表盘
func (g *Gauge) Reset() {
	g.mu.Lock()
	defer g.mu.Unlock()
	g.value = 0
}

// Value 获取仪表盘值
func (g *Gauge) Value() float64 {
	g.mu.Lock()
	defer g.mu.Unlock()
	return g.value
}

// Timer 计时器指标
type Timer struct {
	name       string
	count      int64
	totalTime  float64
	maxTime    float64
	mu         sync.Mutex
	startTimes map[string]time.Time
}

// NewTimer 创建计时器
func NewTimer(name string) *Timer {
	return &Timer{
		name:       name,
		count:      0,
		totalTime:  0,
		maxTime:    0,
		startTimes: make(map[string]time.Time),
	}
}

// Name 获取指标名称
func (t *Timer) Name() string {
	return t.name
}

// Update 更新计时器值
func (t *Timer) Update(value float64) {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.count++
	t.totalTime += value
	if value > t.maxTime {
		t.maxTime = value
	}
}

// Reset 重置计时器
func (t *Timer) Reset() {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.count = 0
	t.totalTime = 0
	t.maxTime = 0
}

// Start 开始计时
func (t *Timer) Start(id string) {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.startTimes[id] = time.Now()
}

// Stop 停止计时
func (t *Timer) Stop(id string) float64 {
	t.mu.Lock()
	defer t.mu.Unlock()

	startTime, ok := t.startTimes[id]
	if !ok {
		return 0
	}

	delete(t.startTimes, id)
	duration := time.Since(startTime).Seconds()

	t.count++
	t.totalTime += duration
	if duration > t.maxTime {
		t.maxTime = duration
	}

	return duration
}

// Avg 获取平均时间
func (t *Timer) Avg() float64 {
	t.mu.Lock()
	defer t.mu.Unlock()
	if t.count == 0 {
		return 0
	}
	return t.totalTime / float64(t.count)
}

// Max 获取最大时间
func (t *Timer) Max() float64 {
	t.mu.Lock()
	defer t.mu.Unlock()
	return t.maxTime
}

// Count 获取计数
func (t *Timer) Count() int64 {
	t.mu.Lock()
	defer t.mu.Unlock()
	return t.count
}

// MetricsCollector 指标收集器
type MetricsCollector struct {
	metrics        map[string]Metric
	metricsMu      sync.RWMutex
	redisClient    *redis.Client
	metricPrefix   string
	collectionDone chan struct{}
	collectPeriod  time.Duration
}

// NewMetricsCollector 创建指标收集器
func NewMetricsCollector(redisClient *redis.Client, metricPrefix string, collectPeriod time.Duration) *MetricsCollector {
	return &MetricsCollector{
		metrics:        make(map[string]Metric),
		redisClient:    redisClient,
		metricPrefix:   metricPrefix,
		collectionDone: make(chan struct{}),
		collectPeriod:  collectPeriod,
	}
}

// RegisterMetric 注册指标
func (mc *MetricsCollector) RegisterMetric(metric Metric) {
	mc.metricsMu.Lock()
	defer mc.metricsMu.Unlock()
	mc.metrics[metric.Name()] = metric
}

// GetCounter 获取计数器
func (mc *MetricsCollector) GetCounter(name string) *Counter {
	mc.metricsMu.RLock()
	metric, ok := mc.metrics[name]
	mc.metricsMu.RUnlock()

	if ok {
		if counter, ok := metric.(*Counter); ok {
			return counter
		}
	}

	// 如果不存在，创建新的计数器
	counter := NewCounter(name)
	mc.RegisterMetric(counter)
	return counter
}

// GetGauge 获取仪表盘
func (mc *MetricsCollector) GetGauge(name string) *Gauge {
	mc.metricsMu.RLock()
	metric, ok := mc.metrics[name]
	mc.metricsMu.RUnlock()

	if ok {
		if gauge, ok := metric.(*Gauge); ok {
			return gauge
		}
	}

	// 如果不存在，创建新的仪表盘
	gauge := NewGauge(name)
	mc.RegisterMetric(gauge)
	return gauge
}

// GetTimer 获取计时器
func (mc *MetricsCollector) GetTimer(name string) *Timer {
	mc.metricsMu.RLock()
	metric, ok := mc.metrics[name]
	mc.metricsMu.RUnlock()

	if ok {
		if timer, ok := metric.(*Timer); ok {
			return timer
		}
	}

	// 如果不存在，创建新的计时器
	timer := NewTimer(name)
	mc.RegisterMetric(timer)
	return timer
}

// Start 开始收集指标
func (mc *MetricsCollector) Start(ctx context.Context) {
	go func() {
		ticker := time.NewTicker(mc.collectPeriod)
		defer ticker.Stop()

		for {
			select {
			case <-ticker.C:
				mc.collectMetrics(ctx)
			case <-ctx.Done():
				close(mc.collectionDone)
				return
			}
		}
	}()
}

// Stop 停止收集指标
func (mc *MetricsCollector) Stop() {
	<-mc.collectionDone
}

// collectMetrics 收集并存储指标
func (mc *MetricsCollector) collectMetrics(ctx context.Context) {
	mc.metricsMu.RLock()
	defer mc.metricsMu.RUnlock()

	timestamp := time.Now().Unix()

	for name, metric := range mc.metrics {
		switch m := metric.(type) {
		case *Counter:
			value := m.Value()
			mc.storeMetric(ctx, name, "counter", value, timestamp)
		case *Gauge:
			value := m.Value()
			mc.storeMetric(ctx, name, "gauge", value, timestamp)
		case *Timer:
			// 存储多个指标
			mc.storeMetric(ctx, name+".avg", "timer", m.Avg(), timestamp)
			mc.storeMetric(ctx, name+".max", "timer", m.Max(), timestamp)
			mc.storeMetric(ctx, name+".count", "timer", float64(m.Count()), timestamp)
		}
	}
}

// storeMetric 存储指标
func (mc *MetricsCollector) storeMetric(ctx context.Context, name, metricType string, value float64, timestamp int64) {
	// 构建指标数据
	metricData := map[string]interface{}{
		"name":      name,
		"type":      metricType,
		"value":     value,
		"timestamp": timestamp,
	}

	// 序列化为JSON
	jsonData, err := json.Marshal(metricData)
	if err != nil {
		log.Printf("序列化指标失败: %v", err)
		return
	}

	// 存储到Redis
	metricKey := fmt.Sprintf("%s:%s:%d", mc.metricPrefix, name, timestamp)
	if err := mc.redisClient.Set(ctx, metricKey, string(jsonData), 24*time.Hour).Err(); err != nil {
		log.Printf("存储指标失败: %v", err)
		return
	}

	// 将指标键添加到时间有序集合
	metricSetKey := fmt.Sprintf("%s:index", mc.metricPrefix)
	if err := mc.redisClient.ZAdd(ctx, metricSetKey, &redis.Z{
		Score:  float64(timestamp),
		Member: metricKey,
	}).Err(); err != nil {
		log.Printf("添加指标索引失败: %v", err)
		return
	}

	// 限制指标数量，删除过旧的数据
	if err := mc.redisClient.ZRemRangeByScore(ctx, metricSetKey, "0", fmt.Sprintf("%d", timestamp-86400)).Err(); err != nil {
		log.Printf("清理过期指标失败: %v", err)
		return
	}
}

// BreakerMetrics 熔断器指标
type BreakerMetrics struct {
	collector       *MetricsCollector
	requestCounter  *Counter
	successCounter  *Counter
	failureCounter  *Counter
	rejectedCounter *Counter
	stateGauge      *Gauge
	latencyTimer    *Timer
}

// NewBreakerMetrics 创建熔断器指标
func NewBreakerMetrics(collector *MetricsCollector, breakerName string) *BreakerMetrics {
	prefix := "breaker." + breakerName
	return &BreakerMetrics{
		collector:       collector,
		requestCounter:  collector.GetCounter(prefix + ".requests"),
		successCounter:  collector.GetCounter(prefix + ".successes"),
		failureCounter:  collector.GetCounter(prefix + ".failures"),
		rejectedCounter: collector.GetCounter(prefix + ".rejected"),
		stateGauge:      collector.GetGauge(prefix + ".state"),
		latencyTimer:    collector.GetTimer(prefix + ".latency"),
	}
}

// RecordRequest 记录请求
func (bm *BreakerMetrics) RecordRequest() {
	bm.requestCounter.Update(1)
}

// RecordSuccess 记录成功
func (bm *BreakerMetrics) RecordSuccess() {
	bm.successCounter.Update(1)
}

// RecordFailure 记录失败
func (bm *BreakerMetrics) RecordFailure() {
	bm.failureCounter.Update(1)
}

// RecordRejected 记录拒绝
func (bm *BreakerMetrics) RecordRejected() {
	bm.rejectedCounter.Update(1)
}

// RecordState 记录状态
func (bm *BreakerMetrics) RecordState(state int) {
	bm.stateGauge.Update(float64(state))
}

// StartTimer 开始计时
func (bm *BreakerMetrics) StartTimer(id string) {
	bm.latencyTimer.Start(id)
}

// StopTimer 停止计时
func (bm *BreakerMetrics) StopTimer(id string) float64 {
	return bm.latencyTimer.Stop(id)
}

// LimiterMetrics 限流器指标
type LimiterMetrics struct {
	collector       *MetricsCollector
	requestCounter  *Counter
	allowedCounter  *Counter
	rejectedCounter *Counter
	latencyTimer    *Timer
}

// NewLimiterMetrics 创建限流器指标
func NewLimiterMetrics(collector *MetricsCollector, limiterName string) *LimiterMetrics {
	prefix := "limiter." + limiterName
	return &LimiterMetrics{
		collector:       collector,
		requestCounter:  collector.GetCounter(prefix + ".requests"),
		allowedCounter:  collector.GetCounter(prefix + ".allowed"),
		rejectedCounter: collector.GetCounter(prefix + ".rejected"),
		latencyTimer:    collector.GetTimer(prefix + ".latency"),
	}
}

// RecordRequest 记录请求
func (lm *LimiterMetrics) RecordRequest() {
	lm.requestCounter.Update(1)
}

// RecordAllowed 记录允许
func (lm *LimiterMetrics) RecordAllowed() {
	lm.allowedCounter.Update(1)
}

// RecordRejected 记录拒绝
func (lm *LimiterMetrics) RecordRejected() {
	lm.rejectedCounter.Update(1)
}

// StartTimer 开始计时
func (lm *LimiterMetrics) StartTimer(id string) {
	lm.latencyTimer.Start(id)
}

// StopTimer 停止计时
func (lm *LimiterMetrics) StopTimer(id string) float64 {
	return lm.latencyTimer.Stop(id)
}
